<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
<title>AngelScript: Debugging scripts</title>

<link href="tabs.css" rel="stylesheet" type="text/css"/>
<link href="doxygen.css" rel="stylesheet" type="text/css" />
<link href="navtree.css" rel="stylesheet" type="text/css"/>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="resize.js"></script>
<script type="text/javascript" src="navtree.js"></script>
<script type="text/javascript">
  $(document).ready(initResizable);
</script>


</head>
<body>
<div id="top"><!-- do not remove this div! -->


<div id="titlearea">
<table cellspacing="0" cellpadding="0">
 <tbody>
 <tr style="height: 56px;">
  
  
  <td style="padding-left: 0.5em;">
   <div id="projectname">AngelScript
   
   </div>
   
  </td>
  
  
  
   
  
 </tr>
 </tbody>
</table>
</div>

<!-- Generated by Doxygen 1.7.5.1 -->
</div>
<div id="side-nav" class="ui-resizable side-nav-resizable">
  <div id="nav-tree">
    <div id="nav-tree-contents">
    </div>
  </div>
  <div id="splitbar" style="-moz-user-select:none;" 
       class="ui-resizable-handle">
  </div>
</div>
<script type="text/javascript">
  initNavTree('doc_debug.html','');
</script>
<div id="doc-content">
<div class="header">
  <div class="headertitle">
<div class="title">Debugging scripts </div>  </div>
</div>
<div class="contents">
<div class="textblock"><p>AngelScript offers a rich interface to support the debugging of scripts. It is easy to build an embedded debugger that can set break points, inspect/manipulate variables in functions, visualize the call stack, etc.</p>
<p>Observe that the CDebugMgr class used in the examples below doesn't exist. It is only used as an abstraction to avoid having to write fictional debug routines.</p>
<dl class="see"><dt><b>See also:</b></dt><dd><a class="el" href="doc_addon_debugger.html">Debugger</a> for a standard implementation</dd></dl>
<h2><a class="anchor" id="doc_debug_1"></a>
Setting line breaks</h2>
<p>In order to break at a specified line in the code the debugger can set the line callback function in the script context. The VM will then invoke the callback for each statement executed, allowing the debugger to decide whether to proceed to the next statement or not.</p>
<div class="fragment"><pre class="fragment"><span class="comment">// An example line callback</span>
<span class="keywordtype">void</span> DebugLineCallback(<a class="code" href="classas_i_script_context.html" title="The interface to the virtual machine.">asIScriptContext</a> *ctx, CDebugMgr *dbg)
{
  <span class="comment">// Determine if we have reached a break point</span>
  <span class="keyword">const</span> <span class="keywordtype">char</span> *scriptSection;
  <span class="keywordtype">int</span> line = ctx-&gt;<a class="code" href="classas_i_script_context.html#adf82981def59c6ec5dd9f74f034be2af" title="Returns the line number at the specified callstack level.">GetLineNumber</a>(0, 0, &amp;scriptSection);
  <a class="code" href="classas_i_script_function.html" title="The interface for a script function description.">asIScriptFunction</a> *<span class="keyword">function</span> = ctx-&gt;<a class="code" href="classas_i_script_context.html#a1c101300447f2909e5d188409a7180f6" title="Returns the function at the specified callstack level.">GetFunction</a>();

  <span class="comment">// Now let the debugger check if a breakpoint has been set here</span>
  <span class="keywordflow">if</span>( dbg-&gt;IsBreakpoint(scriptSection, line, <span class="keyword">function</span>) )
  {
    <span class="comment">// A break point has been reached so the execution of the script should be suspended</span>
    ctx-&gt;<a class="code" href="classas_i_script_context.html#ad4ac8be3586c46069b5870e40c86544a" title="Suspends the execution, which can then be resumed by calling Execute again.">Suspend</a>();
  }
}
</pre></div><p>The line callback is set on the context with the following call:</p>
<div class="fragment"><pre class="fragment">  <span class="comment">// Set the line callback with the address of the debug manager as parameter</span>
  ctx-&gt;<a class="code" href="classas_i_script_context.html#ae2747f643bf9a07364f922c460ef57dd" title="Sets a line callback function. The function will be called for each executed script statement...">SetLineCallback</a>(<a class="code" href="angelscript_8h.html#a78f8f2c7f1c88b12e74a5ac47b4184ae" title="Returns an asSFuncPtr representing the function specified by the name.">asFUNCTION</a>(DebugLineCallback), dbg, <a class="code" href="angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a68ae43cc91cdfc3fa4590c9e6164e4f4" title="A cdecl function.">asCALL_CDECL</a>);
</pre></div><p>When the line callback suspends the execution the context's <a class="el" href="classas_i_script_context.html#a8e52894432737acac2e1a422e496bf84">Execute</a> function will return with the code <a class="el" href="angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a7b5644be315c46f2fa44f032731242c7">asEXECUTION_SUSPENDED</a>. The application can then go into a special message loop where the debug routines can be handled, e.g. to <a class="el" href="doc_debug.html#doc_debug_2">view the call stack</a>, <a class="el" href="doc_debug.html#doc_debug_3">examine variables</a>, etc. Once the execution should continue, simply call the Execute method again to resume it.</p>
<p>An alternative to suspending the script execution might be to start the message loop directly within the line callback, in which case resuming the execution is done simply by returning from the line callback function. Which is the easiest to implement depends on how you have implemented your application.</p>
<h2><a class="anchor" id="doc_debug_2"></a>
Viewing the call stack</h2>
<p>The <a class="el" href="classas_i_script_context.html" title="The interface to the virtual machine.">asIScriptContext</a> exposes the call stack for viewing purposes, so that you can easily track the origin of calls. It is also possible to <a class="el" href="doc_debug.html#doc_debug_3">print the value of variables</a> at each level in the callstack.</p>
<p>Here's an example of how the entire call stack can be printed:</p>
<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> PrintCallstack(<a class="code" href="classas_i_script_context.html" title="The interface to the virtual machine.">asIScriptContext</a> *ctx)
{
  <span class="comment">// Show the call stack</span>
  <span class="keywordflow">for</span>( <a class="code" href="angelscript_8h.html#ac8186f029686800b7ce36bde4a55c815" title="32 bit unsigned integer">asUINT</a> n = 0; n &lt; ctx-&gt;<a class="code" href="classas_i_script_context.html#a88ea15c717f4051cbaffc9623bf01e4b" title="Returns the size of the callstack, i.e. the number of functions that have yet to complete.">GetCallstackSize</a>(); n++ )
  {
    <a class="code" href="classas_i_script_function.html" title="The interface for a script function description.">asIScriptFunction</a> *func;
    <span class="keyword">const</span> <span class="keywordtype">char</span> *scriptSection;
    <span class="keywordtype">int</span> line, column;
    func = ctx-&gt;<a class="code" href="classas_i_script_context.html#a1c101300447f2909e5d188409a7180f6" title="Returns the function at the specified callstack level.">GetFunction</a>(n);
    line = ctx-&gt;<a class="code" href="classas_i_script_context.html#adf82981def59c6ec5dd9f74f034be2af" title="Returns the line number at the specified callstack level.">GetLineNumber</a>(n, &amp;column, &amp;scriptSection);
    printf(<span class="stringliteral">&quot;%s:%s:%d,%d\n&quot;</span>, scriptSection,
                            func-&gt;<a class="code" href="classas_i_script_function.html#a1bb2d5860e1ea3d07a55ba13e6fb26a8" title="Returns the function declaration.">GetDeclaration</a>(),
                            line, column);
  }
}
</pre></div><h2><a class="anchor" id="doc_debug_3"></a>
Inspecting variables</h2>
<p>Through the context interface it is possible to inspect and even modify the value of the local variables on the stack. This can be done for each level in the call stack, and not just the current function that is being executed.</p>
<p>Here is an example for how the variables may be printed:</p>
<div class="fragment"><pre class="fragment"><span class="keywordtype">void</span> PrintVariables(<a class="code" href="classas_i_script_context.html" title="The interface to the virtual machine.">asIScriptContext</a> *ctx, <a class="code" href="angelscript_8h.html#ac8186f029686800b7ce36bde4a55c815" title="32 bit unsigned integer">asUINT</a> stackLevel)
{
  <a class="code" href="classas_i_script_engine.html" title="The engine interface.">asIScriptEngine</a> *engine = ctx-&gt;<a class="code" href="classas_i_script_context.html#a07f12016c5435aec5b63449abb6e4d8d" title="Returns a pointer to the engine.">GetEngine</a>();

  <span class="comment">// First print the this pointer if this is a class method</span>
  <span class="keywordtype">int</span> typeId = ctx-&gt;<a class="code" href="classas_i_script_context.html#a404681f8950c1ebd9382d30ef1ed3b89" title="Returns the type id of the object, if a class method is being executed.">GetThisTypeId</a>(stackLevel);
  <span class="keywordtype">void</span> *varPointer = ctx-&gt;<a class="code" href="classas_i_script_context.html#a4f6761a7a0c872dda681d8e180830ff9" title="Returns a pointer to the object, if a class method is being executed.">GetThisPointer</a>(stackLevel);
  <span class="keywordflow">if</span>( typeId )
  {
    printf(<span class="stringliteral">&quot; this = 0x%x\n&quot;</span>, varPointer);
  }

  <span class="comment">// Print the value of each variable, including parameters</span>
  <span class="keywordtype">int</span> numVars = ctx-&gt;<a class="code" href="classas_i_script_context.html#a3d735c6c7c5a166302cc4ba8ea38e3e8" title="Returns the number of local variables at the specified callstack level.">GetVarCount</a>(stackLevel);
  <span class="keywordflow">for</span>( <span class="keywordtype">int</span> n = 0; n &lt; numVars; n++ )
  {
    <span class="keywordtype">int</span> typeId = ctx-&gt;<a class="code" href="classas_i_script_context.html#a8684e1931e54dbfe53da763fc334413d" title="Returns the type id of a local variable at the specified callstack level.">GetVarTypeId</a>(n, stackLevel); 
    <span class="keywordtype">void</span> *varPointer = ctx-&gt;<a class="code" href="classas_i_script_context.html#acc916505d79de321a2ab2b46b1c61fb7" title="Returns a pointer to a local variable at the specified callstack level.">GetAddressOfVar</a>(n, stackLevel);
    <span class="keywordflow">if</span>( typeId == <a class="code" href="angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aabcc8e086d59505f6ba18ea85e72afc33" title="The type id for int.">asTYPEID_INT32</a> )
    {
      printf(<span class="stringliteral">&quot; %s = %d\n&quot;</span>, ctx-&gt;<a class="code" href="classas_i_script_context.html#ac653a4bd4d155694febf90e76cbea645" title="Returns the declaration of a local variable at the specified callstack level.">GetVarDeclaration</a>(n, stackLevel), *(<span class="keywordtype">int</span>*)varPointer);
    }
    <span class="keywordflow">else</span> <span class="keywordflow">if</span>( typeId == <a class="code" href="angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa43ec6e15e840ebf165070c2ebe9c954d" title="The type id for float.">asTYPEID_FLOAT</a> )
    {
      printf(<span class="stringliteral">&quot; %s = %f\n&quot;</span>, ctx-&gt;<a class="code" href="classas_i_script_context.html#ac653a4bd4d155694febf90e76cbea645" title="Returns the declaration of a local variable at the specified callstack level.">GetVarDeclaration</a>(n, stackLevel), *(<span class="keywordtype">float</span>*)varPointer);
    }
    <span class="keywordflow">else</span> <span class="keywordflow">if</span>( typeId &amp; <a class="code" href="angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa29f9a7c07904452b512431b7b4b5b6e4" title="The bit that shows if the type is a script class.">asTYPEID_SCRIPTOBJECT</a> )
    {
      <a class="code" href="classas_i_script_object.html" title="The interface for an instance of a script object.">asIScriptObject</a> *obj = (<a class="code" href="classas_i_script_object.html" title="The interface for an instance of a script object.">asIScriptObject</a>*)varPointer;
      <span class="keywordflow">if</span>( obj )
        printf(<span class="stringliteral">&quot; %s = {...}\n&quot;</span>, ctx-&gt;<a class="code" href="classas_i_script_context.html#ac653a4bd4d155694febf90e76cbea645" title="Returns the declaration of a local variable at the specified callstack level.">GetVarDeclaration</a>(n, stackLevel));
      <span class="keywordflow">else</span>
        printf(<span class="stringliteral">&quot; %s = &lt;null&gt;\n&quot;</span>, ctx-&gt;<a class="code" href="classas_i_script_context.html#ac653a4bd4d155694febf90e76cbea645" title="Returns the declaration of a local variable at the specified callstack level.">GetVarDeclaration</a>(n, stackLevel));
    }
    <span class="keywordflow">else</span> <span class="keywordflow">if</span>( typeId == engine-&gt;<a class="code" href="classas_i_script_engine.html#ad1f6fecb0f53fd7966736b01f65c3dcb" title="Returns a type id by declaration.">GetTypeIdByDecl</a>(<span class="stringliteral">&quot;string&quot;</span>) )
    {
      <span class="keywordtype">string</span> *str = (<span class="keywordtype">string</span>*)varPointer;
      <span class="keywordflow">if</span>( str )
        printf(<span class="stringliteral">&quot; %s = &#39;%s&#39;\n&quot;</span>, ctx-&gt;<a class="code" href="classas_i_script_context.html#ac653a4bd4d155694febf90e76cbea645" title="Returns the declaration of a local variable at the specified callstack level.">GetVarDeclaration</a>(n, stackLevel), str-&gt;c_str());
      <span class="keywordflow">else</span>
        printf(<span class="stringliteral">&quot; %s = &lt;null&gt;\n&quot;</span>, ctx-&gt;<a class="code" href="classas_i_script_context.html#ac653a4bd4d155694febf90e76cbea645" title="Returns the declaration of a local variable at the specified callstack level.">GetVarDeclaration</a>(n, stackLevel));
    }
    <span class="keywordflow">else</span>
    {
      printf(<span class="stringliteral">&quot; %s = {...}\n&quot;</span>, ctx-&gt;<a class="code" href="classas_i_script_context.html#ac653a4bd4d155694febf90e76cbea645" title="Returns the declaration of a local variable at the specified callstack level.">GetVarDeclaration</a>(n, stackLevel));
    }
  }
}
</pre></div><p>The above code is only an example to give an idea of how it can be done. It is not complete and only recognizes a few types. To make it useful it would have to be expanded to recognize all types, and perhaps add some generic way of converting an object to human readable string for printing.</p>
<p>For script objects that conversion can be done by enumerating the members of an object through the <a class="el" href="classas_i_script_object.html">asIScriptObject</a> interface.</p>
<p>The debugger may also need to be able to inspect the global variables that the functions access. As the global variables are stored in the module, there is the place to look for them. The <a class="el" href="classas_i_script_module.html">asIScriptModule</a> interface can be obtained by querying the module name from the function, and then getting the module pointer from the engine. Once the module is determined the global variables are enumerated much the same way as in the example above, except that the appropriate methods on the <a class="el" href="classas_i_script_module.html" title="The interface to the script modules.">asIScriptModule</a> interface are used instead. </p>
</div></div>
</div>
  <div id="nav-path" class="navpath">
    <ul>

    <li class="footer">Generated on Sun Jan 29 2012 15:41:03 for AngelScript by
    <a href="http://www.doxygen.org/index.html">
    <img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.5.1 </li>
   </ul>
 </div>


</body>
</html>
